import 'dart:async';
import 'dart:convert';
import 'package:convert/convert.dart';
import 'package:crypto/crypto.dart';
import 'package:member_center_sdk/core/member_cllient.dart';
import 'package:member_center_sdk/core/merchant_client.dart';
import 'package:member_center_sdk/core/sdk_config.dart';
import 'package:member_center_sdk/core/sdk_enum.dart';
import 'package:member_center_sdk/grpc/common.pbenum.dart';
import 'package:member_center_sdk/grpc_impl/grpc_result.dart';
import 'package:member_center_sdk/results/auth_result.dart';
import 'package:member_center_sdk/results/base_member_result.dart';
import 'package:member_center_sdk/results/bool_result.dart';
import 'package:member_center_sdk/results/group_info_list_result.dart';
import 'package:member_center_sdk/results/sms_result.dart';
import 'package:member_center_sdk/results/string_result.dart';
import 'package:shared_preferences/shared_preferences.dart';

class SdkCore {
  static const String TOKEN_KEY = "MEMBER_SDK_TOKEN_KEY";
  static const String LAST_AUTH_KEY = "MEMBER_SDK_LAST_AUTH_KEY";
  SdkConfig config;
  MerchantClient _merchantClient;
  Map<String, MemberClient> _memberClients = Map<String, MemberClient>();
  SharedPreferences prefs;
  Map<int, dynamic> cachedMembers = {};

  SdkCore(this.config, this.prefs) {
    _merchantClient = MerchantClient(
        config.host, config.port, config.merchantId, config.signKey);
  }

  MemberClient _getMemberClient(String token) {
    if (!_memberClients.containsKey(token)) {
      _memberClients[token] =
          MemberClient(config.host, config.port, token, (result, token) {
        if (result.code == 9012) {
          var keys = prefs
              .getKeys()
              .where((key) => key.startsWith(TOKEN_KEY))
              .where((key) => (prefs.getString(key) == token))
              .toList();
          if (keys.length > 0) {
            String key = keys.first;
            return prefs.remove(key);
          }
        }
        return false;
      });
    }
    return _memberClients[token];
  }

  /// md5 加密
  String _generateMd5(String data) {
    var content = new Utf8Encoder().convert(data);
    var digest = md5.convert(content);
    // 这里其实就是 digest.toString()
    return hex.encode(digest.bytes);
  }

  /// 设置登录凭据
  Future<bool> setToken(int type, String token) async {
    var grpcResult = await _merchantClient.checkToken(token);
    if (grpcResult.success && grpcResult.result.success) {
      return _setToken(type, token);
    }
    return false;
  }

  Future<bool> _setToken(int type, String token) async {
    bool saved = await prefs.setString("${TOKEN_KEY}_$type", token);
    return saved;
  }

  Future<bool> _removeToken(int type) async {
    return await prefs.remove("${TOKEN_KEY}_$type");
  }

  ///获取TOKEN
  Future<String> getToken(int type) async {
    if (prefs.containsKey("${TOKEN_KEY}_$type")) {
      return prefs.getString("${TOKEN_KEY}_$type");
    }
    return "";
  }

  /// 获取授权
  /// password为明文密码
  Future<AuthResult> pwdAuth(int type, String userName, String password) async {
    password = _generateMd5(password);
    var grpcResult = await _merchantClient.pwdAuth(
        type, userName, password, config.deviceId, config.deviceName);
    if (grpcResult.success) {
      if (grpcResult.result.status == AuthStatus.Success) {
        setCacheUserName(type, userName);
        await _setToken(type, grpcResult.result.token);
        return AuthResult(success: true);
      } else {
        String msg = "";
        switch (grpcResult.result.status) {
          case AuthStatus.PasswordErr:
            msg = "密码错误";
            break;
          case AuthStatus.MemberStatusErr:
            msg = "用户状态不可用";
            break;
          case AuthStatus.NotFound:
            msg = "用户未注册";
            break;
          case AuthStatus.Faild:
            msg = "服务端验证失败";
            break;
          default:
            msg = "未知异常";
            break;
        }
        return AuthResult(message: msg);
      }
    } else {
      return AuthResult(message: grpcResult.message);
    }
  }

  /// 获取用户信息
  Future<bool> getMember<T extends BaseMemberResult>(int type, T info) async {
    String token = await getToken(type);
    if (token.isNotEmpty) {
      var grpcResult = await _getMemberClient(token).getMember();
      if (grpcResult.success) {
        try {
          Map extMap = jsonDecode(grpcResult.result.extJson);
          info.setJson(extMap);
        } catch (ex) {
          print(ex);
        }
        info.userName = grpcResult.result.userName;
        info.memberId = grpcResult.result.memberId.toInt();
        info.avatarUrl = grpcResult.result.avatarUrl;
        return true;
      }
    }
    return false;
  }

  /// 设置上一次登录的用户名
  Future<bool> setCacheUserName(int type, String userName) async {
    return prefs.setString("${LAST_AUTH_KEY}_$type", userName);
  }

  /// 设置扩展数据
  Future<BoolResult> setExt(int type, dynamic data) async {
    String json;
    if (data is String) {
      json = data.toString();
    } else {
      json = jsonEncode(data);
    }
    String token = await getToken(type);
    if (token.isNotEmpty) {
      var grpcResult = await _getMemberClient(token).setExt(json);
      if (grpcResult.success) {
        return BoolResult(true, "", value: grpcResult.result.value);
      } else {
        return BoolResult(false, grpcResult.message);
      }
    } else {
      return BoolResult(false, "请重新登录");
    }
  }

  ///设置头像
  Future<StringResult> setAvater(int type, List<int> data) async {
    String token = await getToken(type);
    if (token.isNotEmpty) {
      var grpcResult = await _getMemberClient(token).setAvater(data);
      if (grpcResult.success) {
        return StringResult(true, "", value: grpcResult.result.avaterUrl);
      } else {
        return StringResult(false, grpcResult.message);
      }
    } else {
      return StringResult(false, "请重新登录");
    }
  }

  /// 获取上一次登录的用户名
  Future<String> getCacheUserName(int type) async {
    return prefs.getString("${LAST_AUTH_KEY}_$type");
  }

  /// 检查用户名是否可用
  Future<bool> checkUserName(String userName) async {
    return false;
  }

  /// 登出
  Future<bool> logout(int type) async {
    return await _removeToken(type);
  }

  /// 发送短信
  Future<SmsResult> sendSms(SmsType type, String phone) async {
    SmsResult result = SmsResult(false, "", "", 0);
    if (phone == null || phone.isEmpty) {
      result.message = "手机号码错误";
    } else if (type == SmsType.Unknow) {
      result.message = "需明确指定短信类型";
    } else {
      var grpcResult =
          await _merchantClient.sendSms(config.deviceId, type.index, phone);
      if (grpcResult.success) {
        if (grpcResult.result.success) {
          result.smsId = grpcResult.result.smsId;
          result.success = grpcResult.result.success;
          result.remainSeconds = 120;
        } else {
          result.remainSeconds = grpcResult.result.remainSeconds;
          result.message = grpcResult.result.message;
        }
        result.message = grpcResult.result.message;
      } else {
        result.message = grpcResult.message;
      }
    }
    return result;
  }

  ///短信授权
  Future<AuthResult> smsAuth(int type, String smsId, String code,
      {bool saveToken = true}) async {
    AuthResult result = AuthResult();
    if (smsId == null || smsId.isEmpty) {
      result.message = "短信Id错误";
    } else if (code == null || code.isEmpty) {
      result.message = "验证未填写";
    } else {
      var grpcResult =
          await _merchantClient.smsAuth(config.deviceName, smsId, code);
      if (grpcResult.success) {
        if (grpcResult.result.status == AuthStatus.Success) {
          if (saveToken) await _setToken(type, grpcResult.result.token);
          return AuthResult(
              success: true,
              token: grpcResult.result.token,
              memberId: grpcResult.result.memberId.toInt());
        } else {
          String msg = "";
          switch (grpcResult.result.status) {
            case AuthStatus.PasswordErr:
              msg = "密码错误";
              break;
            case AuthStatus.MemberStatusErr:
              msg = "用户状态不可用";
              break;
            case AuthStatus.NotFound:
              msg = "用户未注册";
              break;
            case AuthStatus.Faild:
              msg = "服务端验证失败";
              break;
            default:
              msg = "未知异常";
              break;
          }
          return AuthResult(message: msg);
        }
      } else {
        result.message = grpcResult.message;
      }
    }
    return result;
  }

  ///微信授权
  Future<AuthResult> weChatAuth(int type, String wxJson) async {
    AuthResult result = AuthResult();
    if (wxJson == null || wxJson.isEmpty) {
      result.message = "微信JSON错误";
    } else {
      var grpcResult = await _merchantClient.weChatAuth(
          config.deviceName, config.deviceId, wxJson);
      if (grpcResult.success) {
        if (grpcResult.result.status == AuthStatus.Success) {
          await _setToken(type, grpcResult.result.token);
          return AuthResult(
              success: true,
              token: grpcResult.result.token,
              memberId: grpcResult.result.memberId.toInt());
        } else {
          String msg = "";
          switch (grpcResult.result.status) {
            case AuthStatus.PasswordErr:
              msg = "密码错误";
              break;
            case AuthStatus.MemberStatusErr:
              msg = "用户状态不可用";
              break;
            case AuthStatus.NotFound:
              msg = "用户未注册";
              break;
            case AuthStatus.Faild:
              msg = "服务端验证失败";
              break;
            default:
              msg = "未知异常";
              break;
          }
          return AuthResult(message: msg);
        }
      } else {
        result.message = grpcResult.message;
      }
    }
    return result;
  }

  Future<BoolResult> checkPassword(int tokenType, int pwdType) async {
    String token = await getToken(tokenType);
    if (token.isNotEmpty) {
      var grpcResult = await _getMemberClient(token).checkPassword(pwdType);
      if (grpcResult.success) {
        return BoolResult(true, "", value: grpcResult.result.value);
      } else {
        return BoolResult(false, grpcResult.message);
      }
    } else {
      return BoolResult(false, "请重新登录");
    }
  }

  Future<BoolResult> setPassword(int pwdType, String oldPwd, String smsId,
      String code, String newPassword) async {
    newPassword = _generateMd5(newPassword);
    oldPwd = _generateMd5(oldPwd);
    String token = await getToken(pwdType);
    if (token.isNotEmpty) {
      var grpcResult = await _getMemberClient(token)
          .setPassword(pwdType, oldPwd, smsId, code, newPassword);
      if (grpcResult.success) {
        return BoolResult(true, "", value: grpcResult.result.value);
      } else {
        return BoolResult(false, grpcResult.message);
      }
    } else {
      return BoolResult(false, "请重新登录");
    }
  }

  Future<BoolResult> checkParent(int memberId) async {
    var grpcResult = await _merchantClient.checkParent(memberId);
    if (grpcResult.success) {
      return BoolResult(true, "", value: grpcResult.result.value);
    } else {
      return BoolResult(false, grpcResult.message);
    }
  }

  Future<BoolResult> setChild(int tokenType, int memberId) async {
    String token = await getToken(tokenType);
    if (token.isNotEmpty) {
      var grpcResult = await _getMemberClient(token).setChild(memberId);
      if (grpcResult.success) {
        return BoolResult(true, "", value: grpcResult.result.value);
      } else {
        return BoolResult(false, grpcResult.message);
      }
    } else {
      return BoolResult(false, "请重新登录");
    }
  }

  /// 获取用户信息
  Future<bool> getMemberWithMerchant<T extends BaseMemberResult>(
      int memberId, T info) async {
    if (memberId > 0) {
      var grpcResult = await _merchantClient.getMember(memberId);
      if (grpcResult.success) {
        try {
          Map extMap = jsonDecode(grpcResult.result.extJson);
          info.setJson(extMap);
        } catch (ex) {
          print(ex);
        }
        info.userName = grpcResult.result.userName;
        info.memberId = grpcResult.result.memberId.toInt();
        info.avatarUrl = grpcResult.result.avatarUrl;
        return true;
      }
    }
    return false;
  }

  /// 获取用户信息
  Future<bool> getMemberWithUserName<T extends BaseMemberResult>(
      String userName, T info) async {
    if (userName != null && userName.trim().length > 0) {
      var grpcResult = await _merchantClient.getMemberByUserName(userName);
      if (grpcResult.success) {
        try {
          Map extMap = jsonDecode(grpcResult.result.extJson);
          info.setJson(extMap);
        } catch (ex) {
          print(ex);
        }
        info.userName = grpcResult.result.userName;
        info.memberId = grpcResult.result.memberId.toInt();
        info.avatarUrl = grpcResult.result.avatarUrl;
        return true;
      }
    }
    return false;
  }

  Future<GroupInfoListResult> getGroupInfoList(List<String> tokens) async {
    GroupInfoListResult result = GroupInfoListResult(false, "", <GroupInfo>[]);
    if (tokens != null && tokens.length > 0) {
      var grpcResult = await _merchantClient.getGroupInfoList(tokens);
      if (grpcResult.success) {
        result.success = true;
        var groups = grpcResult.result.groups.map((g) {
          return GroupInfo(g.memberId.toInt(), g.userName, g.avatarUrl,
              g.groupCount, g.childCount);
        }).toList();
        result.groupList.addAll(groups);
      } else {
        result.message = grpcResult.message;
      }
    } else {
      result.message = "授权令牌未填写";
    }
    return result;
  }

  Future<BoolResult> bindPhone(int tokenType, String smsId, String code) async {
    String token = await getToken(tokenType);
    if (token.isNotEmpty) {
      var grpcResult = await _getMemberClient(token).bindPhone(smsId, code);
      if (grpcResult.success) {
        return BoolResult(true, "", value: grpcResult.result.value);
      } else {
        return BoolResult(false, grpcResult.message);
      }
    } else {
      return BoolResult(false, "请重新登录");
    }
  }

  Future<BoolResult> combineAccount(
      String userName, String mainToken, List<String> combineTokens) async {
    if (userName == null || userName == "") {
      return BoolResult(false, "用户名不能为空");
    }
    if (mainToken == null || mainToken == "") {
      return BoolResult(false, "主令牌不能为空");
    }
    if (combineTokens == null || combineTokens.length < 1) {
      return BoolResult(false, "需合并的令牌不能为空");
    }
    var grpcResult = await _merchantClient.combineAccount(
        userName, mainToken, combineTokens);
    if (grpcResult.success) {
      return BoolResult(true, "", value: grpcResult.result.value);
    } else {
      return BoolResult(false, grpcResult.message);
    }
  }
}
